#include <util/string.h>
#include <base/log.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <iomanip>
#include <sstream>
#include <algorithm>
#include <string.h>
#include <base/FdMap.hpp>
#include <sys/epoll.h>
namespace util {
namespace string {

size_t Split(const std::string &src_str, const std::string sep, std::vector<std::string> &str_vec)
{
    size_t start_pos = 0;
    size_t end_pos = 0;
    str_vec.clear();
    while (true) {
        end_pos = src_str.find(sep, start_pos);
        const std::string &str_chip = src_str.substr(start_pos, end_pos - start_pos);
        str_vec.push_back(str_chip);
        if (end_pos == std::string::npos)
            break;
        start_pos = end_pos + sep.size();
    }
    return str_vec.size();
}

size_t SplitBySpace(const std::string &src_str, std::vector<std::string> &str_vec)
{
    size_t start_pos = 0;
    size_t end_pos = 0;
    str_vec.clear();
    while (true) {
        start_pos = src_str.find_first_not_of(" \t", end_pos);
        if (start_pos == std::string::npos)
            break;
        end_pos = src_str.find_first_of(" \t", start_pos);
        const std::string &str_chip = src_str.substr(start_pos, end_pos - start_pos);
        str_vec.push_back(str_chip);
        if (end_pos == std::string::npos)
            break;
    }
    return str_vec.size();
}

std::string StripLeft(const std::string &orig_str)
{
    size_t start_pos = orig_str.find_first_not_of(' ', 0);
    if (start_pos == std::string::npos)
        return std::string();
    return orig_str.substr(start_pos);
}

std::string StripRight(const std::string &orig_str)
{
    size_t end_pos = orig_str.find_last_not_of(' ', orig_str.size() - 1);
    if (end_pos == std::string::npos)
        return std::string();
    return orig_str.substr(0, end_pos + 1);
}

std::string Strip(const std::string &orig_str)
{
    size_t start_pos = orig_str.find_first_not_of(' ');
    if (start_pos == std::string::npos)
        return std::string();

    size_t end_pos = orig_str.find_last_not_of(' ');
    if (end_pos == std::string::npos)
        return std::string();

    return orig_str.substr(start_pos, end_pos - start_pos + 1);
}

std::string StripQuot(const std::string &orig_str)
{
    auto first_char = orig_str.front();
    auto last_char = orig_str.back();
    if (first_char == last_char && (first_char == '\'' || first_char == '\"')) {
        return orig_str.substr(1, orig_str.length() - 2);
    } else {
        return orig_str;
    }
}

std::string RawDataToHexStr(const void *data_ptr, uint16_t data_len, bool uppercase, const std::string &delimiter)
{
    if ((data_ptr == NULL) || (data_len == 0))
        return std::string();

    using namespace std;
    ostringstream oss;
    oss << hex << setfill('0');
    if (uppercase)
        oss << std::uppercase;

    const uint8_t *ptr = static_cast<const uint8_t*>(data_ptr);
    for (uint16_t i = 0; i < data_len; ++i) {
        oss << setw(2) << (int)ptr[i];
        if (i < (data_len - 1))
            oss << delimiter;
    }
    return oss.str();
}

namespace {
uint8_t hexCharToValue(char hex_char)
{
    if (('0' <= hex_char) && (hex_char <= '9'))
        return hex_char - '0';
    else if (('A' <= hex_char) && (hex_char <= 'F'))
        return hex_char - 'A' + 10;
    else if (('a' <= hex_char) && (hex_char <= 'f'))
        return hex_char - 'a' + 10;
    else
        throw NotAZaz09Exception();
}

}

size_t HexStrToRawData(const std::string &hex_str, void *out_ptr, uint16_t out_len)
{
    if ((out_ptr == NULL) || (out_len == 0))
        return 0;

    uint8_t *p_data = (uint8_t*)out_ptr;
    size_t data_len = 0;
    for (size_t i = 0; (i < out_len) && ((i * 2 + 1) < hex_str.size()); ++i) {
        char h_char = hex_str[2 * i];
        char l_char = hex_str[2 * i + 1];
        p_data[i] = (hexCharToValue(h_char) << 4) | (hexCharToValue(l_char) & 0x0f);
        ++data_len;
    }
    return data_len;
}

namespace {
void _HexStrToRawDataWithDelimiter(const std::string &hex_str, std::vector<uint8_t> &out, const std::string &delimiter)
{
    auto start_pos = hex_str.find_first_not_of(delimiter);
    while (start_pos != std::string::npos) {
        auto end_pos = hex_str.find_first_of(delimiter, start_pos);
        if (end_pos == std::string::npos)
            end_pos = hex_str.size();

        size_t len = end_pos - start_pos;
        uint8_t value = 0;
        if (len == 1) {
            value = hexCharToValue(hex_str.at(start_pos));
        } else if (len == 2) {
            value = hexCharToValue(hex_str.at(start_pos)) << 4;
            value |= hexCharToValue(hex_str.at(start_pos + 1));
        } else
            throw MoreThan2CharException();

        out.push_back(value);
        start_pos = hex_str.find_first_not_of(delimiter, end_pos);
    }
}

void _HexStrToRawDataWithoutDelimiter(const std::string &hex_str, std::vector<uint8_t> &out)
{
    auto start_pos = hex_str.find_first_not_of(" \t");
    auto end_pos = hex_str.find_last_not_of(" \t") + 1;
    for (size_t i = 0; ((i * 2) < (end_pos - start_pos)); ++i) {
        char h_char = hex_str.at(start_pos + 2 * i);
        char l_char = hex_str.at(start_pos + 2 * i + 1);
        uint8_t value = (hexCharToValue(h_char) << 4) | (hexCharToValue(l_char) & 0x0f);
        out.push_back(value);
    }
}
}

size_t HexStrToRawData(const std::string &hex_str, std::vector<uint8_t> &out, const std::string &delimiter)
{
    out.clear();

    if (delimiter.empty())
        _HexStrToRawDataWithoutDelimiter(hex_str, out);
    else
        _HexStrToRawDataWithDelimiter(hex_str, out, delimiter);

    return out.size();
}

void Replace(std::string &target_str, const std::string &pattern_str, const std::string &replace_str,
             std::string::size_type start, std::string::size_type count)
{
    if (count == 0)
        count = UINT32_MAX;

    std::string::size_type pos = start;
    std::string::size_type pattern_len = pattern_str.size();
    std::string::size_type replace_str_len = replace_str.size();

    while (count > 0 && (pos = target_str.find(pattern_str, pos)) != std::string::npos) {
        target_str.replace(pos, pattern_len, replace_str);
        pos += replace_str_len;
        --count;
    }
}

bool ReadLine(int fd, std::string &line)
{
    char op = 'x';
    while (op != '\n') {
        int res = recv(fd, &op, sizeof(op), 0);
        if (res > 0) {
            if (op == '\r') {
                recv(fd, &op, sizeof(op), MSG_PEEK);
                if (op == '\n') {
                    // 按\r\n结尾的，当前行结束了，读取\n改为\n结尾
                    recv(fd, &op, sizeof(op), 0);
                } else {
                    // 按\r结尾的，手动改成\n结尾
                    op = '\n';    
                }
            }
            line.push_back(op);
        }
        else if (res == 0) {
            // 对端关闭了连接
            close(fd);
            LogInfo("client close fd");
            return false;
        }
        else {
            LogErr("recv error");
            return false;
        }
    }
    return true;
}

void ReadLineEnd(int fd, std::vector<std::string> &lines, std::vector<char>& buffer, std::string& save_line) 
{
     // 处理\r结尾报文,\n结尾报文,\r\n结尾报文
    auto st = buffer.begin();
    auto it = std::find(st, buffer.end(), '\r');
    if (it != buffer.end()) { // 找到'\r',能处理'\r'结尾报文和处理'\r\n'结尾报文
        while ((it = std::find(st, buffer.end(), '\r')) != buffer.end()) {
            if (std::next(it) == buffer.end()) {
                char op;
                auto res = recv(fd, &op, sizeof(op), MSG_PEEK);// 预读不取
                if (res == -1) { // 没有可读内容了，说明是'\r'结尾报文; '\r'结尾强转'\n'结尾
                    *it = '\n';
                    lines.push_back(std::string(st, it));
                    st = std::next(it);
                } else { // 有可读内容
                    if (op == '\n') { // '\r\n'报文在两次读取中
                        recv(fd, &op, sizeof(op), 0);
                        lines.push_back(std::string(st, it));
                        st = std::next(it);
                    } else { // 还有可读内容但是不是'\n'，说明是'\r'结尾报文
                        *it = '\n';
                        lines.push_back(std::string(st, it));
                        st = std::next(it);
                    }
                }
            } else {
                if (*std::next(it) == '\n') { // \n字符,\r\n结尾转成\n结尾 
                    lines.push_back(std::string(st, it));
                    st = std::next(it) + 1;
                } else { // 正常字符,\r结尾强转成\n结尾
                    *it = '\n';
                    lines.push_back(std::string(st, it));
                    st = std::next(it);
                }
            }
        }
        // 清空save_line
        save_line.resize(0);
        // 剩下的就是保留到下次处理的内容
        if (st != buffer.end()) {
            auto pos = std::find(st, buffer.end(), '\0');
            save_line = std::string(st, pos);
        }
        
    } else { // 找到'\n',只用处理'\n'结尾报文
        while ((it = std::find(st, buffer.end(), '\n')) != buffer.end()) {
            lines.push_back(std::string(st, it)); // 保证有'\n'结尾，没有的就是下次处理的
            st = std::next(it);
        }
        // 清空save_line
        save_line.resize(0);
        // 剩下的就是保留到下次处理的内容
        if (st != buffer.end()) {
            auto pos = std::find(st, buffer.end(), '\0');
            save_line = std::string(st, pos);
        }
    }
    // 存储client的<fd, std::string>
    FdMap::GetInstance() -> SetFdMap(fd, save_line);
}

ReadTaskReturnType ReadLineNonBlock(int fd, std::vector<std::string> &lines)
{
    std::string save_line = FdMap::GetInstance() -> FindFdMap(fd);// 读取全局map<fd, std::string>中的数据
    while (1) {
        std::vector<char> buffer;
        buffer.assign(save_line.begin(), save_line.end());
        buffer.resize(save_line.size() + 1024, '\0');
        int pos = save_line.size();
        Retry:
            auto n = recv(fd, &buffer[pos], buffer.size() - 1, 0);
            if (n == -1) {
                if (errno == EAGAIN || errno == EWOULDBLOCK) { 
                    LogErr("data read end: %s, wait next call", strerror(errno));
                    return ReadTaskReturnType::SUCCESS;
                } else { // 异常
                    LogErr("read error: %s", strerror(errno));
                    return ReadTaskReturnType::ERROR;
                }
            } else if (n == 0) { // 发送完毕(可能存在之前的数据结尾，或者本次是全新的数据)或者短连接的情况（对端只发送一次数据，本次数据结尾必须是'\r'或者'\n‘或者'\r\n’, 不然丢包即可）
                ReadLineEnd(fd, lines, buffer, save_line);
                LogInfo("buffer: %s", buffer.data());
                return ReadTaskReturnType::CLIENT_CLOSE;
            }
            // 一个client只会是'\r'或者'\n'或者'\r\n'结尾报文
            // '\n'结尾报文，至少一条;'\r'结尾报文,至少一条;是否'\r\n'结尾报文无法确定('\r''\n'可能被截成两部分，但肯定会因为'\r'跳出)
            if (std::find(buffer.begin(), buffer.end(), '\n') == buffer.end()
                    || std::find(buffer.begin(), buffer.end(), '\r') == buffer.end()) {
                pos = n + 1;
                buffer.resize(buffer.size() * 2);
                goto Retry;
            }
        LogInfo("n = %d", n);
        LogInfo("pos is : %d", pos);
        LogInfo("buffer.size() - 1 : %d", buffer.size() - 1);
        LogInfo("buffer data: %s", buffer.data());
        ReadLineEnd(fd, lines, buffer, save_line);// todo:一次要把buffer里的'\n'读完，每个都是一个line，一次命令
        LogInfo("ReadLineEnd success");
    }
    return ReadTaskReturnType::ERROR;
}

}
}

